#include <core/string.h>
#include <algorithm>
#include <functional>

namespace Core
{
    String::String() : m_buffer(0), m_size(0), m_length(0)
    {
    }

    String::String(const Char* str)
    {
        assign(str);
    }

    String::String(const String& s)
    {
        assign(s);
    }

    String::String(const std::size_t sz)
    {
        alloc(sz);
    }

    String::String(const StdString& s)
    {
        assign(s.c_str());
    }

    String::Char* String::c_str()
    {
        return m_buffer;
    }

    const String::Char* String::c_str() const
    {
        return m_buffer;
    }

    const std::size_t String::length() const
    {
        return m_size;
    }

    bool String::alloc(const std::size_t sz)
    {
        //keep memory
        if(sz <= m_size)
        {
            return false;
        }
        destroy();

        m_buffer = new Char[sz];
        m_buffer[sz - 1] = _T('\0');
        m_size = sz;
        m_length = 0;
        return true;
    }

    void String::clear()
    {
        m_length = 0;
        *m_buffer = _T('\0');
    }

    void String::destroy()
    {
        CORE_DELETE_PTR(m_buffer);
        m_size = 0;
        m_length = 0;
    }

    void String::append(const Char* s)
    {
        String tmp(s);
        append(tmp);
    }

    bool String::empty() const
    {
        return length() == 0;
    }

    void String::append(const String& s)
    {
        if (s.empty())
        {
            return;
        }
        const std::size_t sz = s.length() + 1;
        const std::size_t totalSize = sz + m_length;
        const size_t offset = length();

        //if we can't hold enough, allocate new buffer
        if (capacity() < totalSize)
        {
            Char* allocatedBuffer = new Char[totalSize];
            if (length() != 0)
            {
                _CopyMemory(allocatedBuffer, m_buffer, m_length + 1);
                destroy();
            }
            m_buffer = allocatedBuffer;w
        }
        _CopyMemory(m_buffer + offset, s.m_buffer, sz);

        m_length = totalSize - 1;
        m_size = totalSize;
    }

    const std::size_t String::capacity() const
    {
        return m_size;
    }

    void String::assign(const String& s)
    {
        if (s.empty())
        {
            clear();
            return;
        }
        const std::size_t sz = s.length() + 1;
        alloc(sz);
        _CopyMemory(m_buffer, s.m_buffer, sz);
        m_length = sz - 1;
    }

    void String::assign(const Char* s)
    {
        String tmp(s);
        assign(tmp);
    }

    String& String::operator=(const String& s)
    {
        assign(s);
        return *this;
    }

    String String::operator+(const String& s) const
    {
        String tmp(length() + s.length() + 1);
        tmp = *this;
        tmp.append(s);
        return tmp;
    }
}